package com.informatics.polymer.server.Polymerisation;

import java.io.StringBufferInputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import nu.xom.Document;
import nu.xom.Element;

import org.openscience.cdk.interfaces.IChemFile;
import org.openscience.cdk.interfaces.IChemModel;
import org.openscience.cdk.interfaces.IChemSequence;
import org.openscience.cdk.interfaces.IMolecule;
import org.openscience.cdk.interfaces.IMoleculeSet;
import org.openscience.cdk.io.CMLReader;
import org.openscience.cdk.io.CMLWriter;
import org.openscience.cdk.modeling.builder3d.ModelBuilder3D;
import org.openscience.cdk.modeling.builder3d.TemplateHandler3D;
import org.xmlcml.cml.base.CMLBuilder;
import org.xmlcml.cml.element.CMLAtom;
import org.xmlcml.cml.element.CMLBond;
import org.xmlcml.cml.element.CMLBondArray;
import org.xmlcml.cml.element.CMLFragment;
import org.xmlcml.cml.element.CMLMolecule;
import org.xmlcml.cml.tools.FragmentTool;
import org.xmlcml.cml.tools.SMILESTool;

/**
 * Utility class to help build polymers.
 * 
 * @version 1.0
 * @author eoc21
 * 
 */
public class PolymerisationUtils {
	/**
	 * Boolean to test if polymer can be built.
	 */
	private static boolean canBeBuilt = false;

	/**
	 * Returns an ArrayList<CMLMolecule>, the unjoined repeat unit.
	 * 
	 * @param dp
	 *            - degree of polymerisation, the number of repeat units in the
	 *            polymer.
	 * @param mol
	 *            - CMLMolecule representation to be duplicated.
	 * @param extraID
	 *            - unique string id for the CMLMolecule representation.
	 * @return ArrayList<CMLMolecule>
	 */
	public static ArrayList<CMLMolecule> getRepeatUnitMolecules(final int dp,
			final CMLMolecule mol, final String extraID) {
		ArrayList<CMLMolecule> molecules = new ArrayList<CMLMolecule>();
		for (int i = 0; i < dp; i++) {
			CMLMolecule repeatUnitWithCountExpression = new CMLMolecule();
			for (int j = 0; j < mol.getAtomCount(); j++) {
				CMLAtom a = new CMLAtom();
				a.setAttribute("id", Integer.toString(i) + extraID
						+ mol.getAtom(j).getId());
				a.setAttribute("elementType", mol.getAtom(j).getElementType());
				a.setFormalCharge(mol.getAtom(j).getFormalCharge());
				// Add aromaticity flag
				if (mol.getAtom(j).getAttribute("aromatic") != null) {
					a.setAttribute("aromatic", mol.getAtom(j)
							.getAttributeValue("aromatic"));
				}
				repeatUnitWithCountExpression.addAtom(a);
			}
			for (int j = 0; j < mol.getBondCount(); j++) {
				CMLBond b = new CMLBond();
				String id1 = mol.getBonds().get(j).getAtomId(0);
				String id2 = mol.getBonds().get(j).getAtomId(1);
				b.setAttribute("atomRefs2", Integer.toString(i) + extraID + id1
						+ " " + Integer.toString(i) + extraID + id2);
				b.setId(Integer.toString(i) + extraID + id1 + " "
						+ Integer.toString(i) + extraID + id2);
				b.setOrder(mol.getBonds().get(j).getOrder());
				repeatUnitWithCountExpression.addBond(b);
			}
			molecules.add(repeatUnitWithCountExpression);
		}
		return molecules;
	}

	/**
	 * Joins end groups and repeat unit together to form a connected polymer.
	 * 
	 * @param endgroup1
	 *            - CMLMolecule representation of end group 1.
	 * @param repeatUnit
	 *            - CMLMolecule representation of repeat unit.
	 * @param endgroup2
	 *            - CMLMolecule representation of end group 2.
	 * @param id1
	 *            - Id of the R-group atom in end group 1.
	 * @param id2
	 *            - Id of the first R-group atom in the repeat unit.
	 * @param id3
	 *            - Id of the last R-group atom in the repeat unit.
	 * @param id4
	 *            - Id of the R-group atom in end group 2.
	 * @return CMLMolecule
	 */
	public static CMLMolecule join(final CMLMolecule endgroup1,
			final CMLMolecule repeatUnit, final CMLMolecule endgroup2,
			final String id1, final String id2, final String id3,
			final String id4) {
		for (int j = 0; j < endgroup1.getAtomCount(); j++) {
			CMLAtom a = new CMLAtom();
			a.setAttribute("id", endgroup1.getAtom(j).getId());
			a
					.setAttribute("elementType", endgroup1.getAtom(j)
							.getElementType());
			a.setFormalCharge(endgroup1.getAtom(j).getFormalCharge());
			// Add aromaticity flag
			if (endgroup1.getAtom(j).getAttribute("aromatic") != null) {
				a.setAttribute("aromatic", endgroup1.getAtom(j)
						.getAttributeValue("aromatic"));
			}
			repeatUnit.addAtom(a);
		}

		List<CMLBond> eg1bonds = endgroup1.getBonds();
		for (int i = 0; i < eg1bonds.size(); i++) {
			CMLBond b = new CMLBond();
			b.setAttribute("atomRefs2", eg1bonds.get(i).getAtomId(0) + " "
					+ eg1bonds.get(i).getAtomId(1));
			b.setId(eg1bonds.get(i).getAtomId(0) + " "
					+ eg1bonds.get(i).getAtomId(1));
			b.setOrder("1");
			repeatUnit.addBond(b);
		}

		for (int j = 0; j < endgroup2.getAtomCount(); j++) {
			CMLAtom a = new CMLAtom();
			a.setAttribute("id", endgroup2.getAtom(j).getId());
			a
					.setAttribute("elementType", endgroup2.getAtom(j)
							.getElementType());
			a.setFormalCharge(endgroup2.getAtom(j).getFormalCharge());
			// Add aromaticity flag
			if (endgroup2.getAtom(j).getAttribute("aromatic") != null) {
				a.setAttribute("aromatic", endgroup2.getAtom(j)
						.getAttributeValue("aromatic"));
			}
			repeatUnit.addAtom(a);
		}

		List<CMLBond> eg2bonds = endgroup2.getBonds();
		for (int i = 0; i < eg2bonds.size(); i++) {
			CMLBond b = new CMLBond();
			b.setAttribute("atomRefs2", eg2bonds.get(i).getAtomId(0) + " "
					+ eg2bonds.get(i).getAtomId(1));
			b.setId(eg2bonds.get(i).getAtomId(0) + " "
					+ eg2bonds.get(i).getAtomId(1));
			b.setOrder("1");
			repeatUnit.addBond(b);
		}
		CMLBond cb = new CMLBond();
		cb.setAttribute("atomRefs2", id1 + " " + id2);
		cb.setId(id1 + " " + id2);
		cb.setOrder("1");
		repeatUnit.addBond(cb);
		CMLBond cb2 = new CMLBond();
		cb2.setAttribute("atomRefs2", id3 + " " + id4);
		cb2.setId(id3 + " " + id4);
		cb2.setOrder("1");
		repeatUnit.addBond(cb2);
		// Add the R-R delete bond method on repeatUnit
		ArrayList<CMLBond> bothRAtoms = new ArrayList<CMLBond>();
		CMLBondArray rests = repeatUnit.getBondArray();
		CMLMolecule mNew = null;
		mNew = createNewMoleculeJoinedWithoutRRgroups(rests, bothRAtoms,
				repeatUnit);
		/*
		 * for (int i = 0; i < rests.getBonds().size(); i++) { if
		 * ("R".equals(rests.getBonds().get(i).getAtom(0).getElementType()) &&
		 * "R".equals(rests.getBonds().get(i).getAtom(1).getElementType())) {
		 * bothRAtoms.add(rests.getBonds().get(i)); } } CMLMolecule mNew = null;
		 * for (int i = 0; i < bothRAtoms.size(); i++) { if (i == 0) { RRBonds
		 * rrval = new RRBonds(bothRAtoms.get(i), repeatUnit);
		 * rrval.automaticallySetX1X2(); rrval.createX1X2Bond();
		 * rrval.deleteRgroupsAndBonds(); mNew = rrval.getUpdatedMolecule(); }
		 * else { RRBonds rrval = new RRBonds(bothRAtoms.get(i), mNew);
		 * rrval.automaticallySetX1X2(); rrval.createX1X2Bond();
		 * rrval.deleteRgroupsAndBonds(); mNew = rrval.getUpdatedMolecule(); } }
		 */
		return mNew;
	}

	/**
	 * Converts a SMILE string into a CMLMolecule representation.
	 * 
	 * @param smile
	 *            - SMILE string to be converted into a CMLMolecule
	 *            representation.
	 * @param idVal
	 *            - String id for the new CMLMolecule.
	 * @return CMLMolecule
	 */
	public static CMLMolecule convertSmileString2CML(final String smile,
			final String idVal) {
		CMLMolecule convertedMolecule = new CMLMolecule();
		SMILESTool smilesTool = new SMILESTool();
		smilesTool.parseSMILES(smile);
		convertedMolecule = smilesTool.getMolecule();
		CMLMolecule idCorrectMolecule = new CMLMolecule();
		idCorrectMolecule = addId(convertedMolecule, idVal);
		return idCorrectMolecule;
	}

	/**
	 * This method adds three dimensional coordinates to the generated polymer,
	 * the extension to 3D coordinates is optional and requires the polymer to
	 * have been pre-built, this method depends on the Chemistry Development
	 * Kit, ModelBuilder3D class. NB: Torsion angle is not available to specify
	 * 
	 * @param pmlStringNoCoordinates
	 *            - 2D XML string representation of the built polymer
	 *            ModelBuilder3D class @link
	 *            (http://pele.farmbio.uu.se/nightly/api
	 *            /org/openscience/cdk/modeling/builder3d/ModelBuilder3D.html).
	 * @throws Exception
	 *             if 3D coordinates are not able to be generated.
	 * @return String representation of polymer with 3D coordinates.
	 */
	public static String add3DCoordinates(final String pmlStringNoCoordinates)
			throws Exception {
		StringBufferInputStream r = new StringBufferInputStream(
				pmlStringNoCoordinates);
		CMLReader cr = new CMLReader(pmlStringNoCoordinates);
		cr.setReader(r);
		IChemFile chemFile = null;
		chemFile = (IChemFile) cr.read(new org.openscience.cdk.ChemFile());
		IChemSequence chemSeq = chemFile.getChemSequence(0);
		IChemModel icm = chemSeq.getChemModel(0);
		IMoleculeSet moleculeSet = icm.getMoleculeSet();
		IMolecule m1 = moleculeSet.getMolecule(0);
		ModelBuilder3D mb3d = ModelBuilder3D.getInstance(TemplateHandler3D
				.getInstance(), "mm2");
		IMolecule molWithCoords = mb3d.generate3DCoordinates(m1, true);
		// Write out molecule in cml to see if can view in Jmol
		StringWriter output = new StringWriter();
		CMLWriter cmlWriter = new CMLWriter(output);
		String cmlCode = null;
		cmlWriter.write(molWithCoords);
		cmlCode = output.toString();
		//System.out.println(cmlCode);
		return cmlCode;
	}

	/**
	 * Method returns an array list of CMLAtom if the atom element is R.
	 * 
	 * @param m
	 *            - CMLMolecule to get R-groups from.
	 * @return ArrayList<CMLAtom>.
	 */
	public static ArrayList<CMLAtom> getRElements(final CMLMolecule m) {
		ArrayList<CMLAtom> rGroups = new ArrayList<CMLAtom>();
		for (int i = 0; i < m.getAtomCount(); i++) {
			if ("R".equals(m.getAtom(i).getElementType())) {
				rGroups.add(m.getAtom(i));
			}
		}
		return rGroups;
	}

	/**
	 * Returns a polymerised repeat unit in the form of a CMLMolecule.
	 * 
	 * @param dp
	 *            - degree of polymerisation, an integer value representing the
	 *            number of separate components in the repeat unit.
	 * @param ru
	 *            - CMLMolecule representation of the repeat unit.
	 * @param extraId
	 *            - String value for a unique id added to CMLMolecule.
	 * @return CMLMolecule
	 */
	public static CMLMolecule countExpression(final int dp,
			final CMLMolecule ru, final String extraId) {
		CMLMolecule repeatUnitWithCountExpression = new CMLMolecule();
		for (int i = 0; i < dp; i++) {
			addingAtomsAndBonds(ru, i, extraId, repeatUnitWithCountExpression);
			/*
			 * for (int j = 0; j < ru.getAtomCount(); j++) { CMLAtom a = new
			 * CMLAtom(); a.setAttribute("id", extraId + Integer.toString(i) +
			 * ru.getAtom(j).getId()); a.setAttribute("elementType",
			 * ru.getAtom(j).getElementType());
			 * a.setFormalCharge(ru.getAtom(j).getFormalCharge()); // Add
			 * aromaticity flag if (ru.getAtom(j).getAttribute("aromatic") !=
			 * null) { a.setAttribute("aromatic",
			 * ru.getAtom(j).getAttributeValue( "aromatic")); }
			 * repeatUnitWithCountExpression.addAtom(a); } for (int j = 0; j <
			 * ru.getBondCount(); j++) { CMLBond b = new CMLBond(); String Id1 =
			 * ru.getBonds().get(j).getAtomId(0); String Id2 =
			 * ru.getBonds().get(j).getAtomId(1); b.setAttribute("atomRefs2",
			 * extraId + Integer.toString(i) + Id1 + " " + extraId +
			 * Integer.toString(i) + Id2); b.setId(extraId + Integer.toString(i)
			 * + Id1 + " " + extraId + Integer.toString(i) + Id2);
			 * b.setOrder(ru.getBonds().get(j).getOrder());
			 * repeatUnitWithCountExpression.addBond(b); }
			 */
		}
		// Now add joins between R elements
		ArrayList<CMLAtom> rGroups = new ArrayList<CMLAtom>();
		for (int i = 0; i < repeatUnitWithCountExpression.getAtomCount(); i++) {
			if ("R".equals(repeatUnitWithCountExpression.getAtom(i)
					.getElementType())) {
				rGroups.add(repeatUnitWithCountExpression.getAtom(i));
			}
		}
		ArrayList<CMLBond> rElementBonds = new ArrayList<CMLBond>();
		for (int i = 1; i < rGroups.size() - 1; i++) {
			CMLBond rgroupBond = new CMLBond();
			String id1 = rGroups.get(i).getId();
			String id2 = rGroups.get(i + 1).getId();
			rgroupBond.setAttribute("atomRefs2", id1 + " " + id2);
			rgroupBond.setId(id1 + " " + id2);
			rgroupBond.setOrder("1");
			rElementBonds.add(rgroupBond);
		}
		int counter = 0;
		for (CMLBond cb : rElementBonds) {
			if (counter % 2 == 0) {
				repeatUnitWithCountExpression.addBond(cb);
			}
			counter++;
		}
		/*
		 * Need to extract the atom in a bond with the R-Element, need to delete
		 * bonds to R atoms delete R atom, change neighbour to R element then
		 * add bonds then change to C-atom
		 */
		ArrayList<CMLBond> bothRAtoms = new ArrayList<CMLBond>();
		ArrayList<CMLBond> rFirstAtom = new ArrayList<CMLBond>();
		ArrayList<CMLBond> rLastAtom = new ArrayList<CMLBond>();
		CMLBondArray rests = repeatUnitWithCountExpression.getBondArray();
		for (int i = 0; i < rests.getBonds().size(); i++) {
			CMLBond bond = rests.getBonds().get(i);
			if ("R".equals(bond.getAtom(0).getElementType())
					&& "R".equals(bond.getAtom(1).getElementType())) {
				bothRAtoms.add(bond);
			} else if ("R".equals(bond.getAtom(0).getElementType())) {
				rFirstAtom.add(bond);
			} else if ("R".equals(bond.getAtom(1).getElementType())) {
				rLastAtom.add(bond);
			}
		}

		CMLMolecule mNew = null;
		for (int i = 0; i < bothRAtoms.size(); i++) {
			if (i == 0) {
				RRBonds rrval = new RRBonds(bothRAtoms.get(i),
						repeatUnitWithCountExpression);
				rrval.automaticallySetX1X2();
				rrval.createX1X2Bond();
				rrval.deleteRgroupsAndBonds();
				mNew = rrval.getUpdatedMolecule();
			} else {
				RRBonds rrval = new RRBonds(bothRAtoms.get(i), mNew);
				rrval.automaticallySetX1X2();
				rrval.createX1X2Bond();
				rrval.deleteRgroupsAndBonds();
				mNew = rrval.getUpdatedMolecule();
			}
		}
		return mNew;
	}

	/**
	 * Replaces all R-groups with H.
	 * 
	 * @param m
	 *            - CMLMolecule to which all R-groups will be replaced by H.
	 */
	public static void replaceRWithH(final CMLMolecule m) {
		for (int i = 0; i < m.getAtomCount(); i++) {
			if ("R".equals(m.getAtom(i).getElementType())) {
				m.getAtom(i).setElementType("H");
			}
		}
	}

	/**
	 * Return an XOM document of the built polymer in 2D.
	 * 
	 * @param pDoc
	 *            - Built polymer XOM document.
	 * @return Document representation of polymer.
	 */
	final Polymerisation fromXML(final Document pDoc) {
		return null;
	}

	/**
	 * Method to count the number of occurences of R-groups in a string
	 * representation parsed to constructor for repeat unit and end groups. 1[R]
	 * for end groups and 2[R] for RUs allowed.
	 * 
	 * @param text
	 *            - SMILE string to search against.
	 * @param search
	 *            - String to query smile string (in this case the number of [R]
	 *            groups).
	 * @return int count of fragment searched for.
	 */
	public static int countNumberofFragmentPoints(final String text,
			final String search) {
		int count = 0;
		for (int fromIndex = 0; fromIndex > -1; count++) {
			fromIndex = text.indexOf(search, fromIndex + ((count > 0) ? 1 : 0));
		}
		return count - 1;
	}

	/**
	 * Adds unique id to CMLMolecules for polymerisation constructor.
	 * 
	 * @param convertedMolecule
	 *            - molecule parsed into constructor with no id.
	 * @param idVal
	 *            - unique id value added to the converted molecule to ensure no
	 *            id clashes upon building the polymer.
	 * @return CMLMolecule with unique id.
	 */
	public static CMLMolecule addId(final CMLMolecule convertedMolecule,
			final String idVal) {
		CMLMolecule idCorrectMolecule = new CMLMolecule();
		for (int i = 0; i < convertedMolecule.getAtomCount(); i++) {
			CMLAtom a = new CMLAtom();
			a.setAttribute("id", idVal + convertedMolecule.getAtom(i).getId());
			a.setAttribute("elementType", convertedMolecule.getAtom(i)
					.getElementType());
			a.setFormalCharge(convertedMolecule.getAtom(i).getFormalCharge());
			// Add aromaticity flag
			if (convertedMolecule.getAtom(i).getAttribute("aromatic") != null) {
				a.setAttribute("aromatic", convertedMolecule.getAtom(i)
						.getAttributeValue("aromatic"));
			}
			idCorrectMolecule.addAtom(a);
		}
		for (int i = 0; i < convertedMolecule.getBondCount(); i++) {
			CMLBond b = new CMLBond();
			String id1 = convertedMolecule.getBonds().get(i).getAtomId(0);
			String id2 = convertedMolecule.getBonds().get(i).getAtomId(1);
			b.setAttribute("atomRefs2", idVal + id1 + " " + idVal + id2);
			b.setId(idVal + id1 + " " + idVal + id2);
			b.setOrder(convertedMolecule.getBonds().get(i).getOrder());
			idCorrectMolecule.addBond(b);
		}
		return idCorrectMolecule;
	}

	/**
	 * Gets a list of all the R-Elements within a list of CMLMolecules a
	 * necessary prerequisite for joining molecules.
	 * 
	 * @param moleculeList
	 *            - ArrayList<CMLMolecule> required to find R-groups in each
	 *            molecule in the list
	 * @return ArrayList<ArrayList<String>>
	 */
	public static ArrayList<ArrayList<String>> getRgroupConnectors(
			final ArrayList<CMLMolecule> moleculeList) {
		ArrayList<ArrayList<String>> rgroupIds = new ArrayList<ArrayList<String>>();
		for (int i = 0; i < moleculeList.size(); i++) {
			ArrayList<String> idValues = new ArrayList<String>();
			for (int j = 0; j < moleculeList.get(i).getAtomCount(); j++) {
				if ("R".equals(moleculeList.get(i).getAtom(j).getElementType())) {
					idValues.add(moleculeList.get(i).getAtom(j).getId());
				}
			}
			rgroupIds.add(idValues);
		}
		return rgroupIds;
	}

	/**
	 * Takes an ArrayList<CMLMolecule> and adds bonds from the molecules in the
	 * list into a separate polymer representation (CMLMolecule).
	 * 
	 * @param moleculeList
	 *            - ArrayList of CMLMolecules to add bonds to.
	 * @param i
	 *            - Molecule index
	 * @param polymerRep
	 *            - CMLMolecule representation of the polymer to add bonds to.
	 */
	public static void addBonds(final ArrayList<CMLMolecule> moleculeList,
			final int i, final CMLMolecule polymerRep) {
		List<CMLBond> allBonds = moleculeList.get(i).getBonds();
		for (int j = 0; j < allBonds.size(); j++) {
			CMLBond b = new CMLBond();
			b.setAttribute("atomRefs2", allBonds.get(j).getAtomId(0) + " "
					+ allBonds.get(j).getAtomId(1));
			b.setAttribute("atomRefs2", allBonds.get(j).getAtomId(0) + " "
					+ allBonds.get(j).getAtomId(1));
			b.setId(allBonds.get(j).getAtomId(0) + " "
					+ allBonds.get(j).getAtomId(1));
			b.setOrder(allBonds.get(j).getOrder());
			polymerRep.addBond(b);
		}
	}

	/**
	 * Takes an ArrayList<CMLMolecule> and adds atoms from the molecules in the
	 * list into a separate polymer representation (CMLMolecule).
	 * 
	 * @param molecules
	 *            - ArrayList of CMLMolecules to add bonds to.
	 * @param i
	 *            - Molecule index
	 * @param polymerRep
	 *            - CMLMolecule representation of the polymer to add atoms to.
	 */
	public static void addAtoms(final ArrayList<CMLMolecule> molecules,
			final int i, final CMLMolecule polymerRep) {
		for (int j = 0; j < molecules.get(i).getAtomCount(); j++) {
			CMLAtom a = new CMLAtom();
			a.setAttribute("id", molecules.get(i).getAtom(j).getId());
			a.setAttribute("elementType", molecules.get(i).getAtom(j)
					.getElementType());
			a.setFormalCharge(molecules.get(i).getAtom(j).getFormalCharge());
			// Add aromaticity flag
			if (molecules.get(i).getAtom(j).getAttribute("aromatic") != null) {
				a.setAttribute("aromatic", molecules.get(i).getAtom(j)
						.getAttributeValue("aromatic"));
			}
			polymerRep.addAtom(a);
		}
	}

	/**
	 * Takes existing CMLMolecule representation of the unjoined polymer and
	 * joins up repeat units using X1-R1-R2-X2 bonds then replaces R1-R2 with
	 * X1-X2.
	 * 
	 * @param rests
	 *            - CMLBondArray of all bonds in the polymer.
	 * @param bothRAtoms
	 *            - A list containing all the R-R bonds to be added to the
	 *            unjoined polymer.
	 * @param repeatUnit
	 *            - CMLMolecule representation of the repeat unit.
	 * @return CMLMolecule
	 */
	public static CMLMolecule createNewMoleculeJoinedWithoutRRgroups(
			final CMLBondArray rests, final ArrayList<CMLBond> bothRAtoms,
			final CMLMolecule repeatUnit) {
		for (int i = 0; i < rests.getBonds().size(); i++) {
			if ("R".equals(rests.getBonds().get(i).getAtom(0).getElementType())
					&& "R".equals(rests.getBonds().get(i).getAtom(1)
							.getElementType())) {
				bothRAtoms.add(rests.getBonds().get(i));
			}
		}
		CMLMolecule mNew = null;
		for (int i = 0; i < bothRAtoms.size(); i++) {
			if (i == 0) {
				RRBonds rrval = new RRBonds(bothRAtoms.get(i), repeatUnit);
				rrval.automaticallySetX1X2();
				rrval.createX1X2Bond();
				rrval.deleteRgroupsAndBonds();
				mNew = rrval.getUpdatedMolecule();
			} else {
				RRBonds rrval = new RRBonds(bothRAtoms.get(i), mNew);
				rrval.automaticallySetX1X2();
				rrval.createX1X2Bond();
				rrval.deleteRgroupsAndBonds();
				mNew = rrval.getUpdatedMolecule();
			}
		}
		return mNew;
	}

	/**
	 * Method to add atoms and bonds to a repeat unit.
	 * 
	 * @param ru
	 *            - CMLMolecule representation of the repeat unit.
	 * @param i
	 *            - index.
	 * @param extraId
	 *            - Unique string id for the repeat unit.
	 * @param repeatUnitWithCountExpression
	 *            - CMLMolecule representation of the repeat unit to be built,
	 *            based on joining multiple CMLMolecule ru representations.
	 */
	public static void addingAtomsAndBonds(final CMLMolecule ru, final int i,
			final String extraId,
			final CMLMolecule repeatUnitWithCountExpression) {
		for (int j = 0; j < ru.getAtomCount(); j++) {
			CMLAtom a = new CMLAtom();
			a.setAttribute("id", extraId + Integer.toString(i)
					+ ru.getAtom(j).getId());
			a.setAttribute("elementType", ru.getAtom(j).getElementType());
			a.setFormalCharge(ru.getAtom(j).getFormalCharge());
			// Add aromaticity flag
			if (ru.getAtom(j).getAttribute("aromatic") != null) {
				a.setAttribute("aromatic", ru.getAtom(j).getAttributeValue(
						"aromatic"));
			}
			repeatUnitWithCountExpression.addAtom(a);
		}
		for (int j = 0; j < ru.getBondCount(); j++) {
			CMLBond b = new CMLBond();
			String id1 = ru.getBonds().get(j).getAtomId(0);
			String id2 = ru.getBonds().get(j).getAtomId(1);
			b.setAttribute("atomRefs2", extraId + Integer.toString(i) + id1
					+ " " + extraId + Integer.toString(i) + id2);
			b.setId(extraId + Integer.toString(i) + id1 + " " + extraId
					+ Integer.toString(i) + id2);
			b.setOrder(ru.getBonds().get(j).getOrder());
			repeatUnitWithCountExpression.addBond(b);
		}

	}
	/**
	 * Creates a PML basic document of the built polymer.
	 * @param fragment - CMLFragment for PMLBasic document.
	 * @return Document
	 */
/*	public static final Document createPMLBasic(final CMLFragment fragment) {
		CMLFragment parentFragment = fragment;
		CMLBuilder cmlBuilder = new CMLBuilder();
		Element fragmentRootElement;
		Document basicPMLDoc = null;
		try {
			fragmentRootElement = cmlBuilder
					.parseString(parentFragment.toXML());
			basicPMLDoc = fragmentRootElement.getDocument();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return basicPMLDoc;
	}
*/
	/**
	 * Creates a PML intermediate document of the built polymer.
	 * @param fragment - CMLFragment for PML intermediate document.
	 * @return Document
	 */
/*	public static final Document createPMLIntermediate(final CMLFragment fragment) {
		FragmentTool fragmentTool = FragmentTool.getOrCreateTool(fragment);
		fragmentTool.processBasic();
		CMLBuilder cb = new CMLBuilder();
		Element parentFragmentRootElement;
		Document intermediatePMLDoc = null;
		try {
			parentFragmentRootElement = cb.parseString(fragment.toXML());
			intermediatePMLDoc = parentFragmentRootElement.getDocument();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return intermediatePMLDoc;
	}
*/
	/**
	 * Tests whether the polymer can be built.
	 * @param fragment - CMLFragment which has been built.
	 * @return boolean 
	 */
/*	public static final boolean isBuildable(final CMLFragment fragment) {
		Document pmlIntermediateDoc = createPMLIntermediate(fragment);
		if (pmlIntermediateDoc == null) {
			canBeBuilt  = false;
		} else {
			canBeBuilt = true;
		}
		return canBeBuilt;
	}
	*/
	/**
	 * Method to add blank fragments for PML basic and PML intermediate documents. 
	 * @param repeatUnitAMolecules - ArrayList<CMLMolecule>.
	 * @param blankRepeatUnitsA - ArrayList<CMLMolecule>.
	 * @param repeatUnitBMolecules - ArrayList<CMLMolecule>.
	 * @param blankRepeatUnitsB - ArrayList<CMLMolecule>.
	 * @param blankFragmentsA - ArrayList<CMLFragment>.
	 * @param blankFragmentsB - ArrayList<CMLFragment>.
	 */
	public static final void addBlankFragments(final ArrayList<CMLMolecule>repeatUnitAMolecules,final ArrayList<CMLMolecule> blankRepeatUnitsA,final ArrayList<CMLMolecule> repeatUnitBMolecules,final ArrayList<CMLMolecule>blankRepeatUnitsB,final ArrayList<CMLFragment>blankFragmentsA,final ArrayList<CMLFragment>blankFragmentsB){
		for (int i = 0; i < repeatUnitAMolecules.size(); i++) {
			CMLMolecule m = new CMLMolecule();
			m.setRef("RUA" + Integer.toString(i));
			blankRepeatUnitsA.add(m);
			CMLFragment f = new CMLFragment();
			f.addMolecule(m);
			blankFragmentsA.add(f);
		}
		for (int i = 0; i < repeatUnitBMolecules.size(); i++) {
			CMLMolecule m = new CMLMolecule();
			m.setRef("RUB" + Integer.toString(i));
			blankRepeatUnitsB.add(m);
			CMLFragment f = new CMLFragment();
			f.addMolecule(m);
			blankFragmentsB.add(f);
		}


	}
}
